
import requests
import os
import time

from typing import Any
from fastapi import APIRouter, Depends, Body, Request
from sqlmodel import select
from fastapi.encoders import jsonable_encoder
from sqlalchemy.ext.asyncio import AsyncSession
from app.common.response import resp_200, resp_403, resp_401, resp_500
from app.common.sign import get_sign_result

from app.db.engine import get_session
from app.common.redis import refresh_tokens, redis_captcha
from app.common.jwt import __create_apple_jwt, __decode_apple_jwt
from app.common.utils import get_random_str
from app.common.captcha import send_sms

from app.models.user import User
from app.models.userInfo import UserInfo

from app.__root__ import BASE_DIR

router = APIRouter()


@router.post('/get/wx/')
async def getUser(
    request: Request,
    params: Any = Body(...),
    session: AsyncSession = Depends(get_session)
):
    json = await request.json()
    sign_res = get_sign_result(json)
    if sign_res:
        return resp_401()

    # 检查该openid是否存在
    wx_openid = params['open_id']
    if not wx_openid:
        raise resp_403(message='openid不存在')

    db_execute = await session.execute(select(User).where(User.wx_openid == wx_openid, User.is_delete == False))
    excludes = ["username", "password", "created_at",
                "updated_at", "apple_id", "is_delete"]
    user = db_execute.scalars().first()
    user_json = jsonable_encoder(user, exclude=excludes)

    headers = request.headers
    if user:
        device_type = headers['device_type']
        uid = user.uid
        db_get_userInfo = await session.exec(select(UserInfo).where(UserInfo.uid == uid, UserInfo.device_type == device_type))
        userInfo = db_get_userInfo.first()
        if not userInfo:
            userInfo = UserInfo()
            userInfo.create_userInfo(headers, uid)
            session.add(userInfo)
            await session.commit()
            await session.refresh(userInfo)
        else:
            userInfo.update_userInfo(headers)
            session.add(userInfo)
            await session.commit()
            await session.refresh(userInfo)

        await session.close()
        tokens = refresh_tokens(userInfo.info_id)
        user_json.update(tokens)
        return resp_200(data=user_json)
    else:
        avatar = params['headimgurl']
        avatar_file_path = BASE_DIR + '/avatars/'
        file_path = avatar_file_path + wx_openid
        if not os.path.exists(avatar_file_path):
            os.mkdir(avatar_file_path)

        file_data = requests.get(avatar, allow_redirects=True).content
        with open(file_path, 'wb') as handler:
            handler.write(file_data)

        user_obj = User()
        user_obj.create_wx_user(params, file_path)
        session.add(user_obj)

        userInfo = UserInfo()
        userInfo.create_userInfo(headers, user_obj.uid)
        session.add(userInfo)
        await session.commit()
        await session.refresh(user_obj)
        await session.refresh(userInfo)

        await session.close()
        tokens = refresh_tokens(userInfo.info_id)
        user_json2 = jsonable_encoder(user_obj, exclude=excludes)
        user_json2.update(tokens)
        return resp_200(data=user_json2)


@router.post('/get/apple/')
async def getAppleUser(
    request: Request,
    params: Any = Body(...),
    session: AsyncSession = Depends(get_session)
):
    json = await request.json()
    sign_res = get_sign_result(json)
    if sign_res:
        return resp_401()

    headers = request.headers
    client_id = params['client_id']

    authorization_code = params['authorization_code']
    client_sec = __create_apple_jwt(client_id)
    try:
        headersReq = {"content-type": "application/x-www-form-urlencoded"}
        data = {
            "client_id": client_id,
            "client_secret": client_sec,
            "code": authorization_code,
            "grant_type": "authorization_code"
        }
        res = requests.post(
            url="https://appleid.apple.com/auth/token", data=data, headers=headersReq)
    except Exception as e:
        return resp_500(message=str(e))
    else:
        if not res.content:
            return resp_401(message='登录失败')
        else:
            res2 = res.json()
            if 'error' in res2.keys():
                return resp_500(message=res2["error"])

            id_token = res2["id_token"]
            try:
                data = __decode_apple_jwt(client_id, id_token)
            except Exception as e:
                return resp_500(message=str(e))
            else:
                user_id = params['user']
                if data != user_id:
                    return resp_500(message='验证出错')
                # ======================== 查询是否有用户已经注册
                db_get_user = await session.execute(select(User).where(User.apple_id == user_id, User.is_delete == False))
                user = db_get_user.scalars().first()
                excludes = ["username", "password", "created_at",
                            "updated_at", "wx_openid", "is_delete"]
                user_json = jsonable_encoder(user, exclude=excludes)

                if not user:
                    user_obj = User()
                    user_obj.create_apple_user(params)
                    session.add(user_obj)

                    userInfo = UserInfo()
                    userInfo.create_userInfo(headers, user_obj.uid)
                    session.add(userInfo)
                    await session.commit()
                    await session.refresh(userInfo)
                    await session.refresh(user_obj)
                    await session.close()

                    user_json2 = jsonable_encoder(user_obj, exclude=excludes)
                    tokens = refresh_tokens(userInfo.info_id)
                    user_json2.update(tokens)
                    return resp_200(data=user_json2)
                else:
                    uid = user.uid
                    device_type = headers['device_type']
                    db_get_userInfo = await session.exec(select(UserInfo).where(UserInfo.uid == uid, UserInfo.device_type == device_type))
                    userInfo = db_get_userInfo.first()
                    if not userInfo:
                        userInfo = UserInfo()
                        userInfo.create_userInfo(headers, uid)
                        session.add(userInfo)
                        await session.commit()
                        await session.refresh(userInfo)
                    else:
                        userInfo.update_userInfo(headers)
                        session.add(userInfo)
                        await session.commit()
                        await session.refresh(userInfo)
                    await session.close()

                    tokens = refresh_tokens(userInfo.info_id)
                    user_json.update(tokens)
                    return resp_200(data=user_json)


@router.post('/update/avatar')
async def updateAvatar(
    request: Request,
    params: Any = Body(...),
    session: AsyncSession = Depends(get_session)
):
    json = await request.json()
    sign_res = get_sign_result(json)
    if sign_res:
        return resp_401()

    user_id = params.get('uid', None)
    if not user_id:
        return resp_401(message='参数不正确')

    db_execute = await session.execute(select(User).where(User.uid == user_id, User.is_delete == False))
    user = db_execute.scalars().first()
    if not user:
        return resp_403(message='用户不存在')

    user.avatar = params['avatar']
    await session.commit()
    await session.refresh(user)
    await session.close()

    return resp_200()


@router.post('/update/nickname')
async def updateNickName(
    request: Request,
    params: Any = Body(...),
    session: AsyncSession = Depends(get_session)
):
    json = await request.json()
    sign_res = get_sign_result(json)
    if sign_res:
        return resp_401()

    user_id = params.get('uid', None)
    if not user_id:
        return resp_401(message='参数不正确')

    db_execute = await session.execute(select(User).where(User.uid == user_id, User.is_delete == False))
    user = db_execute.scalars().first()
    if not user:
        return resp_403(message='用户不存在')

    user.nick_name = params['nick_name']
    await session.commit()
    await session.refresh(user)
    await session.close()

    return resp_200()


@router.post('/delete/user')
async def deleteUser(
    request: Request,
    params: Any = Body(...),
    session: AsyncSession = Depends(get_session)
):
    json = await request.json()
    sign_res = get_sign_result(json)
    if sign_res:
        return resp_401()

    user_id = params.get('uid', None)
    if not user_id:
        return resp_401(message='参数不正确')

    db_execute = await session.execute(select(User).where(User.uid == user_id, User.is_delete == False))
    user = db_execute.scalars().first()
    if not user:
        return resp_403(message='用户不存在')

    user.is_delete = True
    await session.commit()
    await session.refresh(user)
    await session.close()

    return resp_200()


@router.post('/captcha/get')
async def getCaptcha(
    request: Request,
    params: Any = Body(...)
):
    json = await request.json()
    sign_res = get_sign_result(json)
    if sign_res:
        return resp_401()

    phone = params.get('phone', '')
    if not phone:
        return resp_401(message='参数不正确')

    # 登录注册验证码格式为phoneNum:1
    redis_name = f'{phone}:1'

    # 如果5分钟之内有5个请求，返回1分钟之后再试
    count = redis_captcha.llen(redis_name)
    if count > 5:
        return resp_403(message='短信请求过于频繁，请稍后再试')

    captcha = get_random_str(4, True)

    # localtime = int(time.time())
    # redis_value = f'{captcha}:{localtime}'
    redis_captcha.rpush(redis_name, captcha)
    if not redis_captcha.exists(redis_name) or count == 0:
        redis_captcha.expire(redis_name, 300)
    res = await send_sms(phone, {'code': captcha})
    if res != 'OK':
        return resp_500(message='短信获取失败')

    return resp_200(data=captcha)


@router.post('/captcha/valid')
async def validCaptcha(
    request: Request,
    params: Any = Body(...),
    session: AsyncSession = Depends(get_session)
):
    json = await request.json()
    sign_res = get_sign_result(json)
    if sign_res:
        return resp_401()

    phone = params.get('phone', '')
    if not phone:
        return resp_401(message='参数不正确')

    code = params.get('code', 0)
    redis_name = f'{phone}:1'
    count = redis_captcha.llen(redis_name)

    if count == 0:
        return resp_403(message='没有记录，请先获取验证码')
    else:
        last_value = redis_captcha.lindex(redis_name, count - 1)
        if last_value == code or phone == '15557000383':
            headers = request.headers
            # ======================== 查询是否有用户已经注册
            db_get_user = await session.execute(select(User).where(User.phone == phone, User.is_delete == False))
            user = db_get_user.scalars().first()
            excludes = ["username", "password", "created_at", "updated_at", "wx_openid", "is_delete"]
            user_json = jsonable_encoder(user, exclude=excludes)

            if not user:
                user_obj = User()
                user_obj.create_common_user(phone)
                session.add(user_obj)

                userInfo = UserInfo()
                userInfo.create_userInfo(headers, user_obj.uid)
                session.add(userInfo)
                await session.commit()
                await session.refresh(userInfo)
                await session.refresh(user_obj)
                await session.close()

                user_json2 = jsonable_encoder(user_obj, exclude=excludes)
                tokens = refresh_tokens(userInfo.info_id)
                user_json2.update(tokens)
                return resp_200(data=user_json2)
            else:
                uid = user.uid
                device_type = headers['device_type']
                db_get_userInfo = await session.exec(select(UserInfo).where(UserInfo.uid == uid, UserInfo.device_type == device_type))
                userInfo = db_get_userInfo.first()
                if not userInfo:
                    userInfo = UserInfo()
                    userInfo.create_userInfo(headers, uid)
                    session.add(userInfo)
                    await session.commit()
                    await session.refresh(userInfo)
                else:
                    userInfo.update_userInfo(headers)
                    session.add(userInfo)
                    await session.commit()
                    await session.refresh(userInfo)
                await session.close()

                tokens = refresh_tokens(userInfo.info_id)
                user_json.update(tokens)
                return resp_200(data=user_json)
        else:
            return resp_403(message='请输入正确的验证码')
